package com.icexxx.icemock.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.icexxx.icemock.mock.ChineseMock;
import com.icexxx.icemock.mock.DateMock;
import com.icexxx.icemock.mock.DoubleMock;
import com.icexxx.icemock.mock.EmailMock;
import com.icexxx.icemock.mock.IceMock;
import com.icexxx.icemock.mock.IdcardMock;
import com.icexxx.icemock.mock.IntMock;
import com.icexxx.icemock.mock.IpMock;
import com.icexxx.icemock.mock.NameMock;
import com.icexxx.icemock.mock.PasswordMock;
import com.icexxx.icemock.mock.PhoneMock;
import com.icexxx.icemock.mock.StrMock;
import com.icexxx.icemock.mock.UuidMock;
import com.icexxx.icemock.mock.UuuuMock;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;

public class Crystallize {
	private static Map<String, List<String>> data = new HashMap<>();

	public static String analysis(String str, Integer index) {
		if (str != null && "@null".equals(StrUtil.trim(str))) {
			return "@null";
		}
		List<String> split = split(str);
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < split.size(); i++) {
			String item = split.get(i);
			item = analysisItem(item, index);
			sb.append(item);
		}
		return sb.toString();
	}

	private static String analysisItem(String str, Integer index) {
		if (str.startsWith("[") && str.endsWith("]")) {
			str = str.substring(1, str.length() - 1);
			List<String> list = splitArray(str);
			String randomEle = RandomUtil.randomEle(list);
			return analysisElement(randomEle, index);
		}
		return analysisElement(str, index);
	}

	private static String analysisElement(String str, Integer index) {
		str = StrUtil.trim(str);
		if (str.startsWith("\"") && str.endsWith("\"")) {
			str = StrUtil.unWrap(str, '"', '"');
			str = str.replace("ƫ", "*+");
			return str;
		}
		return analysisEleWithoutQuotationMark(str, index);
	}

	private static String analysisEleWithoutQuotationMark(String str, Integer index) {
		if (str.contains(".")) {
			str = convertStrWithPoint(str, index);
			return str;
		} else if (str.contains("@")) {
			String key = analysisKey(str);
			if ("@index".equalsIgnoreCase(key) || "@int".equalsIgnoreCase(key)) {
				str = fourFundamentalOperationsSplit(str, index);
				return str;
			} else if ("@double".equalsIgnoreCase(key)) {
				str = fourFundamentalOperationsSplitDouble(str, index);
				return str;
			} else {
				return mockDataByKey(str, index);
			}
		} else {
			return str;
		}
	}

	private static String analysisKey(String str) {
		int length = str.length();
		StringBuilder sb = new StringBuilder();
		sb.append("@");
		for (int i = 1; i < length; i++) {
			char ch = str.charAt(i);
			if (Character.isLetterOrDigit(ch)) {
				sb.append(ch);
			} else {
				break;
			}
		}
		return sb.toString();
	}

	private static String convertStrWithPoint(String str, Integer index) {
		try {
			Double.parseDouble(str);
			return str;
		} catch (NumberFormatException e) {
			if (e.getMessage().contains("For input string:") && e.getMessage().contains(".")) {
				str = fourFundamentalOperationsSplitDouble(str, index);
			}
		}
		try {
			str = fourFundamentalOperationsSplit(str, index);
		} catch (NumberFormatException e) {
			if (e.getMessage().contains("For input string:") && e.getMessage().contains(".")) {
				str = fourFundamentalOperationsSplitDouble(str, index);
			}
		}
		return str;
	}

	private static String mockDataByKey(String str, Integer index) {
		str = StrUtil.trim(str);
		if (str.contains(".")) {
			return dataFromDatabase(str);
		} else if (str.startsWith("@")) {
			int squareBracketsIndex = str.indexOf("[");
			int curvesBracketsIndex = str.indexOf("{");
			String key = str;
			if (curvesBracketsIndex == -1 && squareBracketsIndex == -1) {
				key = str;
			} else if (curvesBracketsIndex == -1 && squareBracketsIndex != -1) {
				key = StrUtil.trim(str.substring(0, squareBracketsIndex));
			} else if (curvesBracketsIndex != -1 && squareBracketsIndex == -1) {
				key = StrUtil.trim(str.substring(0, curvesBracketsIndex));
			} else if (curvesBracketsIndex != -1 && squareBracketsIndex != -1) {
				int min = Math.min(curvesBracketsIndex, squareBracketsIndex);
				key = StrUtil.trim(str.substring(0, min));
			}
			Integer minVal = null;
			Integer maxVal = null;
			Integer minWidth = null;
			Integer maxWidth = null;
			if (str.contains("[") && str.contains("]")) {
				String numRange = StrUtil.subBetween(str, "[", "]");
				List<String> splitTrimNum = StrUtil.splitTrim(numRange, ",");
				int rangeNumlength = splitTrimNum.size();
				if (rangeNumlength == 1) {
					String minValStr = CollUtil.get(splitTrimNum, 0);
					minValStr = StrUtil.trim(minValStr);
					minVal = Integer.parseInt(minValStr);
					maxVal = minVal;
				} else if (rangeNumlength >= 2) {
					String minValStr = CollUtil.get(splitTrimNum, 0);
					minValStr = StrUtil.trim(minValStr);
					minVal = Integer.parseInt(minValStr);
					String maxValStr = CollUtil.get(splitTrimNum, 1);
					maxValStr = StrUtil.trim(maxValStr);
					maxVal = Integer.parseInt(maxValStr);
				}
			}
			if (str.contains("{") && str.contains("}")) {
				String widthRange = StrUtil.subBetween(str, "{", "}");
				List<String> splitTrimWidth = StrUtil.splitTrim(widthRange, ",");
				int rangeWidthlength = splitTrimWidth.size();
				if (rangeWidthlength == 1) {
					String minWidthStr = CollUtil.get(splitTrimWidth, 0);
					minWidthStr = StrUtil.trim(minWidthStr);
					minWidth = Integer.parseInt(minWidthStr);
					maxWidth = minWidth;
				} else if (rangeWidthlength >= 2) {
					String minWidthStr = CollUtil.get(splitTrimWidth, 0);
					minWidthStr = StrUtil.trim(minWidthStr);
					minWidth = Integer.parseInt(minWidthStr);
					String maxWidthStr = CollUtil.get(splitTrimWidth, 1);
					maxWidthStr = StrUtil.trim(maxWidthStr);
					maxWidth = Integer.parseInt(maxWidthStr);
				}
			}
			if ("@int".equalsIgnoreCase(key)) {
				IceMock iceMock = new IntMock();
				return iceMock.mock(minVal, maxVal, minWidth, maxWidth, null, key);
			} else if ("@Str".equalsIgnoreCase(key)) {
				IceMock iceMock = new StrMock();
				return iceMock.mock(minVal, maxVal, minWidth, maxWidth, null, key);
			} else if ("@Double".equalsIgnoreCase(key)) {
				IceMock iceMock = new DoubleMock();
				return iceMock.mock(minVal, maxVal, minWidth, maxWidth, null, key);
			} else if ("@Date".equalsIgnoreCase(key)) {
				IceMock iceMock = new DateMock();
				return iceMock.mock(minVal, maxVal, minWidth, maxWidth, null, key);
			} else if ("@Chinese".equalsIgnoreCase(key)) {
				IceMock iceMock = new ChineseMock();
				return iceMock.mock(minVal, maxVal, minWidth, maxWidth, null, key);
			} else if ("@Name".equalsIgnoreCase(key)) {
				IceMock iceMock = new NameMock();
				return iceMock.mock(minVal, maxVal, minWidth, maxWidth, null, key);
			} else if ("@Phone".equalsIgnoreCase(key)) {
				IceMock iceMock = new PhoneMock();
				return iceMock.mock(minVal, maxVal, minWidth, maxWidth, null, key);
			} else if ("@Email".equalsIgnoreCase(key)) {
				IceMock iceMock = new EmailMock();
				return iceMock.mock(minVal, maxVal, minWidth, maxWidth, null, key);
			} else if ("@IdCard".equalsIgnoreCase(key)) {
				IceMock iceMock = new IdcardMock();
				return iceMock.mock(minVal, maxVal, minWidth, maxWidth, null, key);
			} else if ("@Password".equalsIgnoreCase(key) || "@pwd".equalsIgnoreCase(key)) {
				IceMock iceMock = new PasswordMock();
				return iceMock.mock(minVal, maxVal, minWidth, maxWidth, null, key);
			} else if ("@UUID".equalsIgnoreCase(key)) {
				IceMock iceMock = new UuidMock();
				return iceMock.mock(minVal, maxVal, minWidth, maxWidth, null, key);
			} else if ("@uuuu".equalsIgnoreCase(key)) {
				IceMock iceMock = new UuuuMock();
				return iceMock.mock(minVal, maxVal, minWidth, maxWidth, null, key);
			} else if ("@ip".equalsIgnoreCase(key)) {
				IceMock iceMock = new IpMock();
				return iceMock.mock(minVal, maxVal, minWidth, maxWidth, null, key);
			} else if ("@Index".equalsIgnoreCase(key)) {
				return String.valueOf(index);
			} else {
				return str;
			}
		} else {
			return str;
		}
	}

	private static String dataFromDatabase(String str) {
		List<String> list = data.get(str);
		if (list == null) {
			String tableName = StrUtil.trim(StrUtil.subBefore(str, ".", false));
			String columnName = StrUtil.trim(StrUtil.subAfter(str, ".", false));
			String sql = "select " + columnName + " from " + tableName + " limit 1000";
//			System.out.println(sql);
			list = DatabaseBattery.executeSelectSql(sql, tableName, columnName);
			data.put(str, list);
		}
		String randomEle = RandomUtil.randomEle(list);
		return randomEle;
	}

	private static String fourFundamentalOperationsSplit(String str, Integer index) {
		str = StrUtil.trim(str);
		if (str.contains("ƫ")) {
			String left = StrUtil.trim(StrUtil.subBefore(str, "ƫ", false));
			left = mockDataByKey(left, index);
			String right = StrUtil.trim(StrUtil.subAfter(str, "ƫ", false));
			Long resultNum = Long.parseLong(left) + Long.parseLong(right);
			return String.valueOf(resultNum);
		} else if (str.contains("-")) {
			String left = StrUtil.trim(StrUtil.subBefore(str, "-", false));
			left = mockDataByKey(left, index);
			String right = StrUtil.trim(StrUtil.subAfter(str, "-", false));
			Long resultNum = Long.parseLong(left) - Long.parseLong(right);
			return String.valueOf(resultNum);
		} else if (str.contains("*")) {
			String left = StrUtil.trim(StrUtil.subBefore(str, "*", false));
			left = mockDataByKey(left, index);
			String right = StrUtil.trim(StrUtil.subAfter(str, "*", false));
			Long resultNum = Long.parseLong(left) * Long.parseLong(right);
			return String.valueOf(resultNum);
		} else if (str.contains("/")) {
			String left = StrUtil.trim(StrUtil.subBefore(str, "/", false));
			left = mockDataByKey(left, index);
			String right = StrUtil.trim(StrUtil.subAfter(str, "/", false));
			Long resultNum = Long.parseLong(left) / Long.parseLong(right);
			return String.valueOf(resultNum);
		} else if (str.contains("%")) {
			String left = StrUtil.trim(StrUtil.subBefore(str, "%", false));
			left = mockDataByKey(left, index);
			String right = StrUtil.trim(StrUtil.subAfter(str, "%", false));
			Long resultNum = Long.parseLong(left) % Long.parseLong(right);
			return String.valueOf(resultNum);
		}
		return mockDataByKey(str, index);
	}

	private static String fourFundamentalOperationsSplitDouble(String str, Integer index) {
		str = StrUtil.trim(str);
		if (str.contains("ƫ")) {
			String left = StrUtil.trim(StrUtil.subBefore(str, "ƫ", false));
			left = mockDataByKey(left, index);
			String right = StrUtil.trim(StrUtil.subAfter(str, "ƫ", false));
			Double resultNum = Double.parseDouble(left) + Double.parseDouble(right);
			return String.valueOf(resultNum);
		} else if (str.contains("-")) {
			String left = StrUtil.trim(StrUtil.subBefore(str, "-", false));
			left = mockDataByKey(left, index);
			String right = StrUtil.trim(StrUtil.subAfter(str, "-", false));
			Double resultNum = Double.parseDouble(left) - Double.parseDouble(right);
			return String.valueOf(resultNum);
		} else if (str.contains("*")) {
			String left = StrUtil.trim(StrUtil.subBefore(str, "*", false));
			left = mockDataByKey(left, index);
			String right = StrUtil.trim(StrUtil.subAfter(str, "*", false));
			Double resultNum = Double.parseDouble(left) * Double.parseDouble(right);
			return String.valueOf(resultNum);
		} else if (str.contains("/")) {
			String left = StrUtil.trim(StrUtil.subBefore(str, "/", false));
			left = mockDataByKey(left, index);
			String right = StrUtil.trim(StrUtil.subAfter(str, "/", false));
			Double resultNum = Double.parseDouble(left) / Double.parseDouble(right);
			return String.valueOf(resultNum);
		} else if (str.contains("%")) {
			String left = StrUtil.trim(StrUtil.subBefore(str, "%", false));
			left = mockDataByKey(left, index);
			String right = StrUtil.trim(StrUtil.subAfter(str, "%", false));
			Double resultNum = Double.parseDouble(left) % Double.parseDouble(right);
			return String.valueOf(resultNum);
		}
		return mockDataByKey(str, index);
	}

	private static List<String> splitArray(String str) {
		str = StrUtil.trim(str);
		if (str.endsWith(",")) {
			str = StrUtil.removeSuffix(str, ",");
			str = StrUtil.trim(str);
		}
		List<String> groupList = new ArrayList<>();
		List<String> resultList = new ArrayList<>();
		StringBuilder sb = new StringBuilder();
		int len = str.length();
		boolean flag = false;
		boolean flagSquareBrackets = false;
		boolean flagCurvesBrackets = false;
		for (int i = 0; i < len; i++) {
			char ch = str.charAt(i);
			if (ch == '\"') {
				flag = !flag;

			} else if (ch == ',') {
				if (!flag && !flagSquareBrackets && !flagCurvesBrackets) {
					String content = sb.toString();
					groupList.add(content);
					sb = new StringBuilder();
				} else {
					sb.append(ch);
				}
			} else if (ch == '[') {
				sb.append(ch);
				flagSquareBrackets = true;
			} else if (ch == ']') {
				sb.append(ch);
				flagSquareBrackets = false;
			} else if (ch == '{') {
				sb.append(ch);
				flagCurvesBrackets = true;
			} else if (ch == '}') {
				sb.append(ch);
				flagCurvesBrackets = false;
			} else {
				sb.append(ch);
			}
		}
		String content = sb.toString();
		groupList.add(content);
		for (int i = 0; i < groupList.size(); i++) {
			String span = groupList.get(i);
			span = StrUtil.trim(span);
			resultList.add(span);
		}
		return resultList;
	}

	private static List<String> split(String str) {
		String explanatory = explanatory(str);
		explanatory = explanatory.replace("\\\"", "¦");
		explanatory = explanatory.replace("*+", "ƫ");
		int len = explanatory.length();
		boolean flag = false;
		List<String> groupList = new ArrayList<>();
		List<String> resultList = new ArrayList<>();
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < len; i++) {
			char ch = explanatory.charAt(i);
			if (ch == '"') {
				flag = !flag;
				sb.append(ch);
			} else if (ch == '+') {
				if (!flag) {
					String group = sb.toString();
					groupList.add(group);
					sb = new StringBuilder();
				} else {
					sb.append(ch);
				}
			} else {
				sb.append(ch);
			}
		}
		String group = sb.toString();
		groupList.add(group);
		for (int i = 0; i < groupList.size(); i++) {
			String span = groupList.get(i);
			span = span.replace("¦", "\\\"");
			span = StrUtil.trim(span);
			resultList.add(span);
		}
		return resultList;
	}

	private static String explanatory(String str) {
		str = str.replace("\\\"", "¦");
		int len = str.length();
		boolean flag = false;
		int index = len;
		for (int i = 0; i < len; i++) {
			char ch = str.charAt(i);
			if (ch == '"') {
				flag = !flag;
			} else if (ch == '/') {
				if (i != len - 1) {
					if (!flag && "//".equals(str.substring(i, i + 2))) {
						index = i;
						break;
					}
				}
			}
		}
		String span = str.substring(0, index);
		span = span.replace("¦", "\\\"");
		return span;
	}
}
